home *** CD-ROM | disk | FTP | other *** search
/ MacFormat España 20 / macformat_20.iso / mac / Shareware / Desarrolladores / Sprite Animation Toolkit 2.3.8 / Add-ons / Load faces / FastLoad.p < prev   
Text File  |  1996-06-23  |  15KB  |  378 lines

  1. unit FastLoad;
  2.  
  3. {This unit holds routines for loading faces pointing into parts of offscreen buffers. This is useful for}
  4. {loading large numbers of faces really fast (since it is drawn in one operation, and much fewer Memory}
  5. {Management and Resource Manager operations are needed), but also for odd sprites that "peek" into}
  6. {other parts of offscreens.}
  7.  
  8. {/Ingemar Ragnemalm december 1995 (Revised may 1996)}
  9.  
  10. interface
  11.     uses
  12. {$ifc UNDEFINED THINK_PASCAL}
  13.         Types, QuickDraw, Events, Windows, Dialogs, Fonts, DiskInit, TextEdit, Traps,{}
  14.         Memory, SegLoad, Scrap, ToolUtils, OSUtils, Menus, Resources, StandardFile,{}
  15.         GestaltEqu, Files, Errors, Devices, 
  16. {$endc}
  17.         SAT;
  18.  
  19.     type
  20.         FaceArr = array[0..1000] of Face;
  21.         FaceArrPtr = ^FaceArr;
  22.  
  23. {PeekFaceInOffscreen: A variation on BuildFaceInOffscreen, intended for special effects. It doesn't}
  24. {allocate the face data, but demands that the face already exists. Use it for making a sprite face}
  25. {peek into some image buffer other than its own private one.}
  26.     procedure PeekFaceInOffscreen (var theFace: Face; imageOff, maskOff: SATPort; bounds: Rect;{}
  27.                                     needsRegion, makeRowList: Boolean);
  28.  
  29. {BuildFaceInOffscreen: This is the heart of FastLoad. It builds a face pointing into some image of}
  30. {your choice.}
  31.     procedure BuildFaceInOffscreen (var theFace: Face; imageOff, maskOff: SATPort; bounds: Rect;{}
  32.                                     needsRegion, makeRowList: Boolean);
  33.  
  34. {LoadFaceArray and Load2DFaceArray: High-level functions, for loading faces arrange in arrays}
  35. {in PICTs.}
  36.     function LoadFaceArray (facesPictId, masksPictID: Integer; numFaces, sizeH, sizeV: Integer; {}
  37.                                     needsRegion, makeRowList: Boolean): FaceArrPtr;
  38.     function Load2DFaceArray (facesPictId, masksPictID: Integer; numFaces, sizeH, sizeV: Integer;{}
  39.                                     facesPerRow: Integer; needsRegion, makeRowList: Boolean): FaceArrPtr;
  40.  
  41. {Note: The two Booleans needsRegion and makeRowList, used in all routines above, tell whether you}
  42. {want certain extra data in the face. Set needsRegion to true if you want to run your program to run}
  43. {as fast as possible WITHOUT blitters, using only QuickDraw. Set makeRowList of you want it to run}
  44. {with optimal speed WITH blitters. If both are false, it will load extremely fast, but the animation may}
  45. {not run quite as fast.}
  46.  
  47. {This routine is in SAT.lib, but not in the interface files! It is for internal use by the unit.}
  48.     procedure SATMakeRowList (portRect: Rect; baseAddr: Ptr; rowBytes: integer; var rows: Ptr; depth: Integer);
  49.  
  50. implementation
  51.  
  52.     type
  53.         BMPtr = ^BitMap;
  54.  
  55.         FourBitStuff = record
  56.                 evenData, oddData: Ptr;
  57.                 oddMask: BitMap;
  58.                 oddRowBytes: integer;
  59.                 destRect: Rect; {Behövs för safe}
  60.                 oddRows, oddMaskRows: Ptr;
  61.             end;
  62.         FourBitPtr = ^FourBitStuff;
  63.  
  64.  
  65. {BuildFaceInOffscreen builds a face that points into two offscreen imgaes, one for the image data}
  66. {and one for the mask. This can be used for loading faces quickly, but also for making weirds}
  67. {sprites who peek into other parts of the screen.}
  68. {}
  69. {This will probably NEVER get really good in 4-bit color.}
  70.  
  71.     procedure BuildFaceInOffscreen (var theFace: Face; imageOff, maskOff: SATPort; bounds: Rect; needsRegion, makeRowList: Boolean);
  72.     begin
  73.         theFace.iconMask.baseAddr := Ptr(Longint(maskOff.baseAddr) + Longint(maskOff.rowBytes) * bounds.top + bounds.left div 8); {32 pixels wide = 4 bytes wide in B/W}
  74.         theFace.iconMask.rowBytes := maskOff.rowBytes;
  75.         theFace.iconMask.bounds := bounds;
  76.         OffsetRect(theFace.iconMask.bounds, -theFace.iconMask.bounds.left, -theFace.iconMask.bounds.top);
  77.  
  78.         if gSAT.initDepth = 1 then
  79.             begin
  80.                 theFace.colorData := NewPtrClear(sizeOf(BitMap));
  81.                 if theFace.colorData <> nil then
  82.                     begin
  83.                         BMPtr(theFace.colorData)^.bounds := theFace.iconMask.bounds;
  84.                         BMPtr(theFace.colorData)^.rowBytes := imageOff.rowBytes;
  85.                         BMPtr(theFace.colorData)^.baseAddr := Ptr(Longint(imageOff.baseAddr) + Longint(imageOff.rowBytes) * bounds.top + bounds.left div 8);
  86.                         if makeRowList then
  87.                             SATMakeRowList(bounds, BMPtr(theFace.colorData)^.baseAddr, BMPtr(theFace.colorData)^.rowBytes, theFace.rows, 1);
  88.                     end;
  89.             end
  90.         else if gSAT.initDepth = 4 then
  91. {4-bit isn't good, since we have no shifted version of the offscreen being pointed into. I support it halfway just}
  92. {since it is better than crashing.}
  93.             begin
  94.                 theFace.colorData := NewPtrClear(sizeof(FourBitStuff));
  95.  
  96.                 if theFace.colorData <> nil then
  97.                     with FourBitPtr(theFace.colorData)^ do
  98.                         begin
  99.                             theFace.rowBytes := imageOff.rowBytes;
  100.                             evenData := Ptr(Longint(imageOff.baseAddr) + Longint(imageOff.rowBytes) * bounds.top + bounds.left * gSAT.initDepth div 8);
  101.                             if makeRowList then
  102.                                 SATMakeRowList(bounds, evenData, theFace.rowBytes, theFace.rows, 4);
  103.  
  104.                             oddRowBytes := imageOff.rowBytes;
  105.                             oddData := Ptr(Longint(imageOff.baseAddr) + Longint(imageOff.rowBytes) * bounds.top + bounds.left * gSAT.initDepth div 8);
  106.  
  107.                             destRect := theFace.iconMask.bounds;
  108. {OffsetRect(destRect, 1, 0);}
  109.                             if makeRowList then
  110.                                 SATMakeRowList(destRect, oddData, oddRowBytes, oddRows, 4);
  111.  
  112.                             BlockMove(@theFace.iconMask, @oddMask, SizeOf(BitMap));
  113. {oddMask.bounds.left := 0; {Måste ha origo rätt!}
  114.                             oddRows := nil;
  115.                             oddMaskRows := nil;
  116.  
  117.                             if makeRowList then
  118.                                 SATMakeRowList(oddMask.bounds, oddMask.baseAddr, oddMask.rowBytes, oddMaskRows, 1);
  119.                             if makeRowList then
  120.                                 SATMakeRowList(theFace.iconMask.bounds, theFace.iconMask.baseAddr, theFace.iconMask.rowBytes, theFace.maskRows, 1);
  121.                         end;
  122.             end
  123.         else
  124.             begin
  125.                 theFace.colorData := Ptr(Longint(imageOff.baseAddr) + Longint(imageOff.rowBytes) * bounds.top + bounds.left * gSAT.initDepth div 8);
  126.                 if makeRowList then
  127.                     SATMakeRowList(bounds, theFace.colorData, theFace.rowBytes, theFace.rows, gSAT.initDepth);
  128.                 if makeRowList then
  129.                     SATMakeRowList(theFace.iconMask.bounds, theFace.iconMask.baseAddr, theFace.iconMask.rowBytes, theFace.maskRows, 1);
  130.             end;
  131.  
  132.         theFace.rowBytes := imageOff.rowBytes;
  133.         theFace.next := nil;
  134. {Build region. This is time consuming, but can be skipped if we only draw with blitters - but that means}
  135. {giving up the safety backdoor! Another option is to use on region for several masks, when we know some masks}
  136. {are equal.}
  137.         if needsRegion then
  138.             begin
  139.                 theFace.maskRgn := NewRgn;
  140.                 if noErr <> BitMapToRegion(theFace.maskRgn, theFace.iconMask) then
  141.                     ;
  142.             end
  143.         else
  144.             theFace.maskRgn := nil;
  145. {Arrays of row starts. I skip them for now, though they are advisable when using blitters. They are pretty}
  146. {easy to make though: just a pointer to an array of pointers, where each points to the first byte in each row.}
  147.         theFace.rows := nil;
  148.         theFace.maskRows := nil;
  149. {Hooks that we don't use here:}
  150.         theFace.redrawProc := nil;
  151.         theFace.drawProc := nil;
  152.     end; {BuildFaceInOffscreen}
  153.  
  154.  
  155. {PeekFaceInOffscreen is very similar to BuildFaceInOffscreen, but doesn't build the face, but just changes its}
  156. {pointers to another place in the offscreens, in order to change where it points. You can then have it pointing}
  157. {anywhere, into other ports, to the screen etc. However, if the memory it points to changes, sprites using}
  158. {the face may have to set their "dirty" flag in order to work with SATRun2!}
  159. {The only difference to BuildFaceInOffscreen is that it doesn't allocate pointers.}
  160.  
  161.     procedure PeekFaceInOffscreen (var theFace: Face; imageOff, maskOff: SATPort; bounds: Rect; needsRegion, makeRowList: Boolean);
  162.     begin
  163.         theFace.iconMask.baseAddr := Ptr(Longint(maskOff.baseAddr) + Longint(maskOff.rowBytes) * bounds.top + bounds.left div 8); {32 pixels wide = 4 bytes wide in B/W}
  164.         theFace.iconMask.rowBytes := maskOff.rowBytes;
  165.         theFace.iconMask.bounds := bounds;
  166.         OffsetRect(theFace.iconMask.bounds, -theFace.iconMask.bounds.left, -theFace.iconMask.bounds.top);
  167.  
  168.         if gSAT.initDepth = 1 then
  169.             begin
  170. {theFace.colorData := NewPtrClear(sizeOf(BitMap));}
  171.                 if theFace.colorData <> nil then
  172.                     begin
  173.                         BMPtr(theFace.colorData)^.bounds := theFace.iconMask.bounds;
  174.                         BMPtr(theFace.colorData)^.rowBytes := imageOff.rowBytes;
  175.                         BMPtr(theFace.colorData)^.baseAddr := Ptr(Longint(imageOff.baseAddr) + Longint(imageOff.rowBytes) * bounds.top + bounds.left div 8);
  176.                         if makeRowList then
  177.                             SATMakeRowList(bounds, BMPtr(theFace.colorData)^.baseAddr, BMPtr(theFace.colorData)^.rowBytes, theFace.rows, 1);
  178.                     end;
  179.             end
  180.         else if gSAT.initDepth = 4 then
  181. {4-bit isn't good, since we have no shifted version of the offscreen being pointed into. I support it halfway just}
  182. {since it is better than crashing.}
  183.             begin
  184. {theFace.colorData := NewPtrClear(sizeof(FourBitStuff));}
  185.  
  186.                 if theFace.colorData <> nil then
  187.                     with FourBitPtr(theFace.colorData)^ do
  188.                         begin
  189.                             theFace.rowBytes := imageOff.rowBytes;
  190.                             evenData := Ptr(Longint(imageOff.baseAddr) + Longint(imageOff.rowBytes) * bounds.top + bounds.left * gSAT.initDepth div 8);
  191.                             if makeRowList then
  192.                                 SATMakeRowList(bounds, evenData, theFace.rowBytes, theFace.rows, 4);
  193.  
  194.                             oddRowBytes := imageOff.rowBytes;
  195.                             oddData := Ptr(Longint(imageOff.baseAddr) + Longint(imageOff.rowBytes) * bounds.top + bounds.left * gSAT.initDepth div 8);
  196.  
  197.                             destRect := theFace.iconMask.bounds;
  198. {OffsetRect(destRect, 1, 0);}
  199.                             if makeRowList then
  200.                                 SATMakeRowList(destRect, oddData, oddRowBytes, oddRows, 4);
  201.  
  202.                             BlockMove(@theFace.iconMask, @oddMask, SizeOf(BitMap));
  203. {oddMask.bounds.left := 0; {Måste ha origo rätt!}
  204.                             oddRows := nil;
  205.                             oddMaskRows := nil;
  206.  
  207.                             if makeRowList then
  208.                                 SATMakeRowList(oddMask.bounds, oddMask.baseAddr, oddMask.rowBytes, oddMaskRows, 1);
  209.                             if makeRowList then
  210.                                 SATMakeRowList(theFace.iconMask.bounds, theFace.iconMask.baseAddr, theFace.iconMask.rowBytes, theFace.maskRows, 1);
  211.                         end;
  212.             end
  213.         else
  214.             begin
  215.                 theFace.colorData := Ptr(Longint(imageOff.baseAddr) + Longint(imageOff.rowBytes) * bounds.top + bounds.left * gSAT.initDepth div 8);
  216.                 if makeRowList then
  217.                     SATMakeRowList(bounds, theFace.colorData, theFace.rowBytes, theFace.rows, gSAT.initDepth);
  218.                 if makeRowList then
  219.                     SATMakeRowList(theFace.iconMask.bounds, theFace.iconMask.baseAddr, theFace.iconMask.rowBytes, theFace.maskRows, 1);
  220.             end;
  221.  
  222.         theFace.rowBytes := imageOff.rowBytes;
  223.         theFace.next := nil;
  224. {Build region. This is time consuming, but can be skipped if we only draw with blitters - but that means}
  225. {giving up the safety backdoor! Another option is to use on region for several masks, when we know}
  226. {some masks are equal.}
  227.         if needsRegion then
  228.             begin
  229.                 if theFace.maskRgn = nil then
  230.                     theFace.maskRgn := NewRgn;
  231.                 if noErr <> BitMapToRegion(theFace.maskRgn, theFace.iconMask) then
  232.                     ;
  233.             end
  234.         else
  235.             theFace.maskRgn := nil;
  236. {Arrays of row starts. I skip them for now, though they are advisable when using blitters. They are pretty}
  237. {easy to make though: just a pointer to an array of pointers, where each points to the first byte in each row.}
  238.         theFace.rows := nil;
  239.         theFace.maskRows := nil;
  240. {Hooks that we don't use here:}
  241.         theFace.redrawProc := nil;
  242.         theFace.drawProc := nil;
  243.     end; {PeekFaceInOffscreen}
  244.  
  245.  
  246. {CreateBWOffscreen is useful for creating a B/W offscreeen buffer for masks}
  247.  
  248.     procedure CreateBWOffscreen (var portP: SATPort; frame: Rect);
  249.         var
  250.             savePort: GrafPtr;
  251.     begin
  252.         GetPort(savePort);
  253.  
  254.         portP.device := nil;
  255.         portP.port := GrafPtr(NewPtr(sizeof(GrafPort)));
  256.         OpenPort(portP.port);
  257.         portP.port^.portRect := frame;
  258.         portP.port^.portBits.bounds := portP.port^.portRect;
  259.  
  260.         RectRgn(portP.port^.visRgn, frame);
  261.         ClipRect(frame);
  262.  
  263.         portP.port^.portBits.rowBytes := longint(((portP.port^.portRect.right - portP.port^.portRect.left + 31) div 32) * 4);
  264.         portP.port^.portBits.baseAddr := NewPtr(portP.port^.portBits.rowBytes * longint(portP.port^.portRect.bottom - portP.port^.portRect.top));
  265.  
  266.         SetPort(portP.port);
  267.         EraseRect(portP.port^.portRect);
  268.  
  269.         portP.baseAddr := portP.port^.portBits.baseAddr;
  270.         portP.bounds := portP.port^.portBits.bounds;
  271.         portP.rowBytes := portP.port^.portBits.rowBytes;
  272.  
  273. {with portP.port^ do}
  274. {SATMakeRowList(portRect, portBits.baseAddr, portBits.rowBytes, portP.rows, 1);}
  275.  
  276.         SetPort(savePort);
  277.     end; {CreateBWOffscreen}
  278.  
  279. {LoadFaceArray loads a set of faces to a one-dimensional array of faces, arranged vertically in a PICT}
  280. {resource. You can easily extend it to 2-dimensional arrays if you like.}
  281. {NOT TESTED!}
  282.  
  283.     function LoadFaceArray (facesPictId, masksPictID: Integer; numFaces, sizeH, sizeV: Integer; {}
  284.                                     needsRegion, makeRowList: Boolean): FaceArrPtr;
  285.         var
  286.             fr, mr: Rect;
  287.             facesOff, masksOff: SATPort;
  288.             i: Integer;
  289.             faces: FaceArrPtr;
  290.             facesPict, masksPict: PicHandle;
  291.             bounds: Rect;
  292.     begin
  293.         LoadFaceArray := nil;
  294.         faces := FaceArrPtr(NewPtr(SizeOf(Face) * numFaces));
  295.         if faces = nil then
  296.             Exit(LoadFaceArray);
  297.  
  298.         facesPict := GetPicture(facesPictId);
  299.         masksPict := GetPicture(masksPictID);
  300.  
  301.         fr := facesPict^^.picFrame;
  302.         OffsetRect(fr, -fr.left, -fr.top);
  303.  
  304.         SATMakeOffscreen(facesOff, fr);
  305.         SATSetPort(facesOff);
  306.         DrawPicture(facesPict, fr);
  307.  
  308.         mr := masksPict^^.picFrame;
  309.         OffsetRect(mr, -mr.left, -mr.top);
  310.  
  311.         CreateBWOffscreen(masksOff, mr);
  312.         SATSetPort(masksOff);
  313.         DrawPicture(masksPict, mr);
  314.  
  315.         ReleaseResource(Handle(facesPict));
  316.         ReleaseResource(Handle(masksPict));
  317.  
  318. {This routine assumes that we have numFaces faces of sizeH*sizeV pixels with masks in the two pictures!}
  319.  
  320.         for i := 0 to numFaces - 1 do
  321.             begin
  322.                 SetRect(bounds, 0, i * sizeV, sizeH, (i + 1) * sizeV);
  323.                 BuildFaceInOffscreen(faces^[i], facesOff, masksOff, bounds, needsRegion, makeRowList);
  324.             end;
  325.  
  326.         LoadFaceArray := faces;
  327.     end; {LoadFaceArray}
  328.  
  329.     function Load2DFaceArray (facesPictId, masksPictID: Integer; numFaces, sizeH, sizeV: Integer; {}
  330.                                     facesPerRow: Integer; needsRegion, makeRowList: Boolean): FaceArrPtr;
  331.         var
  332.             fr, mr: Rect;
  333.             facesOff, masksOff: SATPort;
  334.             i, h, v: Integer;
  335.             faces: FaceArrPtr;
  336.             facesPict, masksPict: PicHandle;
  337.             bounds: Rect;
  338.     begin
  339.         Load2DFaceArray := nil;
  340.         faces := FaceArrPtr(NewPtr(SizeOf(Face) * numFaces));
  341.         if faces = nil then
  342.             Exit(Load2DFaceArray);
  343.  
  344.         facesPict := GetPicture(facesPictId);
  345.         masksPict := GetPicture(masksPictID);
  346.  
  347.         fr := facesPict^^.picFrame;
  348.         OffsetRect(fr, -fr.left, -fr.top);
  349.  
  350.         SATMakeOffscreen(facesOff, fr);
  351.         SATSetPort(facesOff);
  352.         DrawPicture(facesPict, fr);
  353.  
  354.         mr := masksPict^^.picFrame;
  355.         OffsetRect(mr, -mr.left, -mr.top);
  356.  
  357.         CreateBWOffscreen(masksOff, mr);
  358.         SATSetPort(masksOff);
  359.         DrawPicture(masksPict, mr);
  360.  
  361.         ReleaseResource(Handle(facesPict));
  362.         ReleaseResource(Handle(masksPict));
  363.  
  364. {This routine assumes that we have numFaces faces of sizeH*sizeV pixels with masks in the two pictures,}
  365. {arranged with facesPerRow faces per row!}
  366.  
  367.         for i := 0 to numFaces - 1 do
  368.             begin
  369.                 h := i mod facesPerRow;    {0..facesPerRow-1}
  370.                 v := i div facesPerRow;        {0 and up}
  371.                 SetRect(bounds, h * sizeH, v * sizeV, (h + 1) * sizeH, (v + 1) * sizeV);
  372.                 BuildFaceInOffscreen(faces^[i], facesOff, masksOff, bounds, needsRegion, makeRowList);
  373.             end;
  374.  
  375.         Load2DFaceArray := faces;
  376.     end; {Load2DFaceArray}
  377.  
  378. end.